const http = require("http");
const path = require("path");
const fse = require('fs-extra');
const multiparty = require("multiparty"); // 这个包处理 formData  Formdata和数据格式今天要处理掉
const server = http.createServer();
const UPLOAD_DIR = path.resolve(__dirname, '..', "target");
// 提取后缀名
const extractExt = filename => {
    return filename.slice(filename.lastIndexOf("."),filename.length); // 提取后缀名
}
const extractFxt = filename =>{
    return filename.slice(0,filename.lastIndexOf("."));
}
// 解析请求
const resolvePost = (req) => {
    return new Promise(resolve => {
        let chunk = '';
        req.on("data", data => {
            chunk += data;
        })
        req.on("end", () => {
            resolve(JSON.parse(chunk));
        })
    })

}

const pipeStream = (path, writeStream) => {
    return new Promise(resolve => {
        const readStream = fse.createReadStream(path);

        readStream.on("end", () => {
            fse.unlinkSync(path);
            console.log('合并文件')
            resolve();
        });
        readStream.pipe(writeStream);
    });
}

// 合并切片
/**
 * 
 * @param {*} filePath  // 最终合成的文件
 * @param {*} filename // 外置文件夹名称
 * @param {*} size 
 */
const mergeFileChunk = async (filePath, filename, size) => {
   const chunkDir = path.resolve(UPLOAD_DIR,filename);
    //const chunkDir = path.resolve(UPLOAD_DIR);
    const chunkPaths = await fse.readdir(chunkDir);

    // 根据切片下标进行排序
    // 否则直接读取会出错 这里排序也不对
    chunkPaths.sort((a, b) => {
        return parseInt(a.split("-")[1]) - parseInt(b.split("-")[1]);
    })
    console.log(chunkDir, chunkPaths, filePath, filename);
    await Promise.all(
        chunkPaths.map((chunkPath, index) =>
            pipeStream(
                path.resolve(chunkDir, chunkPath),
                // 指定位置创建可写流
                fse.createWriteStream(filePath, {
                    start: index * size,
                    end: (index + 1) * size
                })
            )
        )
    );
    fse.rmdirSync(chunkDir); // 合并后删除保存切片的目录
}
// 返回已经上传切片名列表
const createUploadedList = async (fileHash) =>{
  return  fse.existsSync(path.resolve(UPLOAD_DIR,fileHash))?await fse.readdir(path.resolve(UPLOAD_DIR,fileHash)):[];
}
server.on("request", async (req, res) => {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "*");
    if (req.method === "OPTIONS") {
        res.status = 200;
        res.end();
        return;
    }
    if(req.url === "/verify"){
        console.log('验证请求')
        const data = await resolvePost(req);
        const {fileHash,filename} = data;
        const ext = extractExt(filename);
        const filePath = path.resolve(UPLOAD_DIR,`${fileHash}${ext}`);
        if(fse.existsSync(filePath)){
            res.end(
                JSON.stringify({
                    shouldUpload:false
                })
            )
        }else{
            res.end(
                JSON.stringify({
                    shouldUpload:true,
                    uploadedList:await createUploadedList(fileHash)
                })
            )
        }
    }
    if (req.url === "/merge") {
        const data = await resolvePost(req);
        const { filename, size,hash } = data;
        const Fxfilename = hash;
        
        const ext = extractExt(filename);
        const filePath = path.resolve(UPLOAD_DIR, `${hash}${ext}`);
        await mergeFileChunk(filePath, Fxfilename, size);
        res.end(
            JSON.stringify({
                code: 0,
                message: "file merged success"
            })
        )
    }
    // multiparty处理切片
    const multipart = new multiparty.Form();
    multipart.parse(req, async (err, fields, files) => {
        if (err) {
            return;
        }
        const [chunk] = files.chunk;
        const [hash] = fields.hash;
        const [fileHash] = fields.fileHash;
        const [filename] = fields.filename;
        const filePreName = extractFxt(filename)
       // const chunkDir = path.resolve(UPLOAD_DIR,filename);
        const chunkDir = path.resolve(UPLOAD_DIR,fileHash);
        // 切片目录不在 创建切片目录
        if (!fse.existsSync(chunkDir)) {
            await fse.mkdirs(chunkDir);
        }
        // 创建接收切片
        await fse.move(chunk.path, `${chunkDir}/${hash}`);
        res.end('传递结束')
    })

})


server.listen(3000, () => console.log("正在监听 3000d端口"))